package com.csii.adhoc.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.extension.service.IService;
import com.csii.adhoc.annotation.Excel;
import com.csii.adhoc.exception.ParamValidityException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;

/**
 * @description: 基础controller
 * @author: panChuanJiang
 * @create: 2021-07-02 10:19
 */
public class BaseController<T, S extends IService<T>> {
    private static final Logger log = LoggerFactory.getLogger(BaseController.class);
    @Autowired
    private S service;

    protected String importExcel(MultipartFile request, Class<T> tClass) throws Exception{
        String fileName = request.getOriginalFilename();
        if (fileName != null && !fileName.endsWith("xls") && !fileName.endsWith("xlsx")) {
            throw new ParamValidityException("不支持的文件格式");
        }
        try (InputStream inputStream = request.getInputStream();
             ExcelReader reader = ExcelUtil.getReader(inputStream)) {
            List<Map<String, Object>> maps = reader.readAll();

            List<T> list = convertMapToBean(tClass, maps);
            service.saveBatch(list);
        }
        return "success";
    }

    /**
     * 导出
     *
     * @param response     输出流
     * @param pcjAdhocTest 实体类
     * @param tClass       导入类class
     * @param tableName    表名
     */
    protected void exportXls(HttpServletResponse response, T pcjAdhocTest, Class<T> tClass, String tableName) {
        List<T> list = service.list();
        ExcelWriter writer = ExcelUtil.getWriter();
        Field[] fields = tClass.getDeclaredFields();
        Arrays.stream(fields).forEach(x -> {
            Excel annotation = x.getAnnotation(Excel.class);
            if (annotation != null) {
                writer.addHeaderAlias(x.getName(), annotation.name());
            }
        });
        //一次性写出内容，使用默认样式，强制输出标题
        writer.write(list, true);
        writer.autoSizeColumnAll();
        try {
            tableName = URLEncoder.encode(tableName, "utf-8");
        } catch (UnsupportedEncodingException e) {
            log.error("UnsupportedEncodingException", e);
        }
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + tableName + ".xls");
        ServletOutputStream excelOut = null;
        try {
            excelOut = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.flush(excelOut, true);
        writer.close();
        IoUtil.close(excelOut);
    }

    private List<T> convertMapToBean(Class<T> tClass, List<Map<String, Object>> maps) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        Field[] fields = tClass.getDeclaredFields();
        Map<String, String> fieldNames = new HashMap<>();
        //读取所有有Excel注释的字段
        Arrays.stream(fields).forEach(x -> {
            Excel annotation = x.getAnnotation(Excel.class);
            if (annotation != null) {
                fieldNames.put(annotation.name(), x.getName());
            }
        });
        List<T> list = new ArrayList<>();
        //map转bean
        for (Map<String, Object> map : maps) {
            T t = tClass.newInstance();
            for (String key : map.keySet()) {
                if (fieldNames.containsKey(key)) {
                    Field field = tClass.getDeclaredField(fieldNames.get(key));
                    field.setAccessible(true);
                    field.set(t, map.get(key));
                }
            }
            list.add(t);
        }
        return list;
    }
}
